package com.mezz.bones.im.logic.dev.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.mezz.bones.framework.base.domain.response.Result;
import com.mezz.bones.im.logic.strategy.ImCallbackStrategyFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Slf4j
@Api("IM回调接口")
@RequestMapping("/no-auth/im/callback")
@RestController
public class ImNotifyController {

    @Resource
    private ImCallbackStrategyFactory callbackStrategyFactory;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // nonce过期时间（毫秒）
    private static final long NONCE_EXPIRE_TIME = 5 * 60 * 1000; // 5分钟
    private static final String NONCE_KEY_PREFIX = "im:callback:nonce:";

    @PostMapping
    @ApiOperation("IM回调")
    public Result<?> imCallback(@RequestHeader("sign") String sign, HttpEntity<byte[]> httpEntity) {

        // 获取原始字节数组
        byte[] rawBodyBytes = httpEntity.getBody();

        // 转换为UTF-8字符串（不处理转义）
        String body = new String(rawBodyBytes, StandardCharsets.UTF_8);

        log.info("收到IM回调请求, body: {}, sign: {}", body, sign);

        try {
            // 解析请求体
            JSONObject jsonBody = JSONObject.parseObject(body);
            String nonce = jsonBody.getString("nonce");
            Long timestamp = jsonBody.getLong("timestamp");

            // 验证时间戳
            if (!verifyTimestamp(timestamp)) {
                log.error("时间戳验证失败, timestamp: {}", timestamp);
                return Result.error("请求已过期");
            }

            // 验证nonce
            if (!verifyAndSaveNonce(nonce)) {
                log.error("Nonce验证失败, nonce: {}", nonce);
                return Result.error("重复的请求");
            }

            // 验证签名
            if (!verifySign(sign, body)) {
                log.error("签名验证失败, sign: {}, body: {}", sign, body);
                return Result.error("签名验证失败");
            }

            // 使用策略模式处理不同事件
            // 抛出异常code 消息不会落库
            return Result.OK(callbackStrategyFactory.processCallback(body));
        } catch (Exception e) {
            log.error("处理IM回调异常", e);
            return Result.error(e.getMessage());
        }
    }

    /**
     * 验证时间戳
     */
    private boolean verifyTimestamp(Long timestamp) {
        if (timestamp == null) {
            return false;
        }
        long currentTime = System.currentTimeMillis();
        return Math.abs(currentTime - timestamp) <= NONCE_EXPIRE_TIME;
    }

    /**
     * 验证并保存nonce
     */
    private boolean verifyAndSaveNonce(String nonce) {
        if (StrUtil.isBlank(nonce)) {
            return false;
        }
        String key = NONCE_KEY_PREFIX + nonce;
        Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", NONCE_EXPIRE_TIME, TimeUnit.MILLISECONDS);
        return Boolean.TRUE.equals(success);
    }

    /**
     * 验证签名
     */
    private boolean verifySign(String sign, String body) {
        String appSecret = "dev-0d427b5c01d438e9a1666e72345316ab752ac409567dde941b297fa264453314182";
        String plaintext = StrUtil.concat(true, appSecret, body);
        String calculatedSign = SecureUtil.sha256(plaintext);
        log.debug("IM签名 | 明文:{} | 签名:{}", plaintext, sign);
        return calculatedSign.equals(sign);
    }
}
